package com.zeta.system.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.idev.excel.read.listener.ReadListener;
import cn.idev.excel.write.handler.WriteHandler;
import com.zeta.system.model.dto.SysDictItemDTO;
import com.zeta.system.model.entity.SysDict;
import com.zeta.system.model.entity.SysDictItem;
import com.zeta.system.model.param.SysDictItemSaveDTO;
import com.zeta.system.model.param.SysDictItemUpdateDTO;
import com.zeta.system.model.poi.SysDictItemExportVO;
import com.zeta.system.model.poi.SysDictItemImportVO;
import com.zeta.system.model.query.SysDictItemQueryDTO;
import com.zeta.system.poi.listener.SysDictItemImportListener;
import com.zeta.system.service.ISysDictItemService;
import com.zeta.system.service.ISysDictService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zetaframework.annotation.satoken.PreAuth;
import org.zetaframework.annotation.satoken.PreCheckPermission;
import org.zetaframework.base.excel.handler.MergeHandler;
import org.zetaframework.base.result.ApiResult;
import org.zetaframework.controller.SuperController;
import org.zetaframework.controller.extra.PoiController;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 字典项 前端控制器
 *
 * @author AutoGenerator
 */
@RequiredArgsConstructor
@Tag(name = "字典项", description = "60.字典项")
@PreAuth(replace = "sys:dictItem")
@RestController
@RequestMapping("/system/dictItem")
public class SysDictItemController extends SuperController<ISysDictItemService, Long, SysDictItem, SysDictItemQueryDTO, SysDictItemSaveDTO, SysDictItemUpdateDTO>
    implements PoiController<SysDictItemImportVO, SysDictItemExportVO, SysDictItem, SysDictItemQueryDTO>
{
    private final ISysDictService dictService;

    /**
     * 根据字典编码查询字典项
     *
     * @param codes List<String>
     */
    @PreCheckPermission(value = "{}:view")
    @Operation(summary = "根据字典编码查询字典项")
    @PostMapping("/codeList")
    public ApiResult<Map<String, List<SysDictItemDTO>>> codeList(
            @RequestBody @Parameter(description = "字典code") List<String> codes) {
        Assert.notEmpty(codes, "字典code不能为空");
        return success(service.listByCodes(codes));
    }

    /**
     * <p>注册导出Excel 自定义写处理器</p>
     * <p>
     * 说明：<br>
     * 如果你要导出的excel中有一些额外信息，请重写本方法
     * <p>
     * 参考：<br>
     * <a href="https://fast-excel.github.io/fastexcel/zh-cn/docs/write/extra#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8B%A6%E6%88%AA%E5%99%A8">自定义拦截器</a>
     *
     * @param handlers 写处理器列表
     */
    @Override
    public void registerExportWriteHandlers(List<WriteHandler> handlers) {
        // 注册-合并单元格处理器 (合并字典id、字典名称列相同的数据)
        handlers.add(new MergeHandler(1, new int[]{1, 2}));
    }

    /**
     * <p>注册导入数据监听器</p>
     * <p>
     * 说明：
     * <pre>
     * 1.你需要手动实现导入监听器，来处理导入的数据
     * 2.不要将Listener交给Spring管理。
     * </pre>
     * 相关文档：
     * <a href="https://fast-excel.github.io/fastexcel/zh-cn/docs/help/faq#%E5%B9%B6%E5%8F%91%E8%AF%BB%E5%8F%96">为何不能将Listener交给Spring管理？</a>
     */
    @Override
    public ReadListener<SysDictItemImportVO> getReadListener() {
        return new SysDictItemImportListener(service);
    }

    /**
     * 获取待导出的数据
     *
     * @param param 查询参数 不可为空
     * @return List<ExportBean>
     */
    @Override
    public List<SysDictItemExportVO> findExportList(SysDictItemQueryDTO param) {
        // 条件查询Entity数据
        List<SysDictItem> list = super.handlerBatchQuery(param);
        if (list.isEmpty()) { return Collections.emptyList(); }

        // 字典数据缓存
        Map<Long, SysDict> dictCacheMap = new HashMap<>();

        // List<Entity> -> List<ExportBean>
        List<SysDictItemExportVO> exportList = list.stream().map(it -> {
            SysDictItemExportVO exportVO = BeanUtil.toBean(it, SysDictItemExportVO.class);

            // 通过id查询字典数据并缓存。说明：保证每个字典只查一次数据库
            SysDict dict = dictCacheMap.get(it.getDictId());
            if (dict == null) {
                dict = dictService.getById(it.getDictId());
                dictCacheMap.put(it.getDictId(), dict);
            }

            // 设置字典名
            exportVO.setDictName(dict != null ? dict.getName() : "");
            return exportVO;
        }).toList();

        dictCacheMap.clear();
        return exportList;
    }
}

